﻿/*
///    This file is part of BannerLib4Net.
///
///    BannerLib4Net is free software: you can redistribute it and/or modify
///    it under the terms of the GNU General Public License as published by
///    the Free Software Foundation, either version 3 of the License, or
///    (at your option) any later version.

///    BannerLib4Net is distributed in the hope that it will be useful,
///    but WITHOUT ANY WARRANTY; without even the implied warranty of
///    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
///    GNU General Public License for more details.
///
///    You should have received a copy of the GNU General Public License
///    along with BannerLib4Net.  If not, see <http://www.gnu.org/licenses/>.
*/


using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;

using BannerLib4Net.Core.Logging;
using BannerLib4Net.Data.Configuration;
using Npgsql;


namespace BannerLib4Net.Postgresql
{
    public class Connection : IDbConnection, IDisposable
    {
        private const int defaultPort = 5432;
        private const int defaultTimeout = 60;

        private NpgsqlConnection PGConnection { get; set; }
        public String ConnectionString { get; set; }
        private ILogger Log { get; set; }

        public Connection(String connectionString)
        {
           Initialize(connectionString); 
        }

        public void Initialize(String connectionString)
        {
            Log = LoggingFactory.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.ToString());
            Log.LogDebug(String.Format("Initializing connection class with the following connection settings: {0}", connectionString));
            this.ConnectionString = connectionString;

            PGConnection = new NpgsqlConnection(this.ConnectionString);
            PGConnection.Notification += HandlePgSQLNotification;
            
        }

        ///<summary>
        ///Callback method that handles messages from the server
        ///</summary>
        private void HandlePgSQLNotification(Object sender, NpgsqlNotificationEventArgs args)
        {
            Log.LogDebug(args.Condition);   
        }

        public bool ExecuteStatement(String statement)
        {
            IDbCommand cmd = null;
            Boolean success = false;

            if (!String.IsNullOrEmpty(statement))
            {
                try
                {

                    this.Open();

                    Log.LogDebug(String.Format("Opened postgresql connection ... "));

                    cmd = this.CreateCommand();
                    cmd.CommandText = statement;
                    cmd.CommandType = CommandType.Text;

                    Log.LogDebug(String.Format("Beginning transaction ... "));
                    cmd.Transaction = this.BeginTransaction();

                    Log.LogDebug(String.Format("Executing statement {0}", statement));
                    cmd.ExecuteNonQuery();
                    Log.LogDebug(String.Format("Statement was executed successfully ..."));
                    Log.LogDebug(String.Format("Committing transaction ... "));

                    cmd.Transaction.Commit();

                    success = true;
                    Log.LogDebug(String.Format("Was transaction successful?: {0} ... ", success));

                }
                catch (Exception ex)
                {

					Console.WriteLine(String.Format("Exception Message: {0}", ex.Message));
					Console.WriteLine(String.Format("Exception Source: {0}", ex.Source));
					Console.WriteLine(String.Format("Exception StackTrace: {0}", ex.StackTrace));


                    Log.LogWarn(String.Format("Could not execute sql: {0}", statement));

                    Log.LogError(ex.Message);

                    cmd.Transaction.Rollback();

                    if (this.PGConnection != null)
                    {
                        this.PGConnection.Close();
                    }
                    success = false;
                }
                finally
                {
                    Log.LogDebug(String.Format("Execute statement finished, closing connection ... "));
                    if (this.PGConnection != null) { this.PGConnection.Close(); }
                }
            }


            return success;
        }

        public IDbTransaction BeginTransaction()
        {
            return PGConnection.BeginTransaction();
        }

        public IDbTransaction BeginTransaction(IsolationLevel il)
        {
            return PGConnection.BeginTransaction(il);
        }

        public void ChangeDatabase(string databaseName)
        {
            PGConnection.ChangeDatabase(databaseName);
        }

        public void Close()
        {
            PGConnection.Close();
        }

        public IDbCommand CreateCommand()
        {
            return PGConnection.CreateCommand();
        }

        public void Open()
        {
            try
            {
                PGConnection.Open();
            }
            catch (Exception ex)
            {
                Log.LogError(String.Format("An exception occurred trying to open the postgresql connection using Connection String: {0}", this.ConnectionString), ex);

				Console.WriteLine(String.Format("Exception Message: {0}", ex.Message));
				Console.WriteLine(String.Format("Exception Source: {0}", ex.Source));
				Console.WriteLine(String.Format("Exception StackTrace: {0}", ex.StackTrace));


            }
        }

        public int ConnectionTimeout
        {
            get
            {
                return PGConnection.ConnectionTimeout;
            }
        }

        public string Database
        {
            get
            {
                return this.PGConnection.Database;
            }
        }

        public ConnectionState State
        {
            get
            {
                return PGConnection.State;
            }
        }

        public void Dispose()
        {
            if (this.PGConnection.State == ConnectionState.Open)
            {
                this.PGConnection.Close();
                this.PGConnection.Dispose();
                Log.LogDebug(String.Format("Disposed postgresql connection ... "));
            }
        }
	
    }
}
